#include"Mesh.h"


void Mesh::CreateVertexBuffer(int nVertices)
{
	CreateVB(D3DDevice, &vertexBuffer, vertexData, nVertices, vertexType);
}

void Mesh::CreateIndexBuffer(int nIndices)
{
	CreateIB(D3DDevice, &indexBuffer, indexData, nIndices);
}

void Mesh::Create(int nVertices, int nIndices, VertexType type)
{
	vertexType = type;
	numVertices = nVertices;
	numTriangles = nIndices / 3;

	switch(vertexType){
		case XYZ:
			sizeofVertex = 12;
			vertexData = positionData;
			break;
		case XYZ_UV:
			sizeofVertex = 20;
			vertexData = new VertexUV[nVertices];
			for(int i = 0; i < nVertices; ++i){
				VertexUV vert = VertexUV(positionData[i].x, positionData[i].y, positionData[i].z, 
										uvData[i].x, uvData[i].y);
				((VertexUV*)vertexData)[i] = vert;
			}
			break;
		case XYZ_N:
			sizeofVertex = 24;
			vertexData = new VertexN[nVertices];
			for(int i = 0; i < nVertices; ++i){
				VertexN vert = VertexN(positionData[i].x, positionData[i].y, positionData[i].z, 
										normalData[i].x, normalData[i].y, normalData[i].z);
				((VertexN*)vertexData)[i] = vert;
			}
			break;
		case XYZ_UV_N:
			sizeofVertex = 32;
			vertexData = new VertexUVN[nVertices];
			for(int i =0; i < nVertices; ++i){
				VertexUVN vert = VertexUVN(positionData[i].x, positionData[i].y, positionData[i].z, 
										uvData[i].x, uvData[i].y, 
										normalData[i].x, normalData[i].y, normalData[i].z);
				((VertexUVN*)vertexData)[i] = vert;
			}
	}

	CreateVertexBuffer(nVertices);
	CreateIndexBuffer(nIndices);

}

D3DXMATRIX Mesh::LocalToWorldMatrix()
{
	D3DXMATRIX matScale, matRot, matTrans;
	D3DXMatrixScaling(&matScale, scale.x, scale.y, scale.z);
	D3DXMatrixTranslation(&matTrans, position.x, position.y, position.z);
	matRot = rotation.matrix();

	return matScale * matRot * matTrans;

}

void Mesh::SetVertexDeclaration()
{
	switch(vertexType){
	case XYZ:
		{
			D3DVERTEXELEMENT9 NMVertexElements[] =  {
				{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},      
				D3DDECL_END()
			};
			if(vertexDecl)
				SAFE_RELEASE(vertexDecl);
			D3DDevice->CreateVertexDeclaration(NMVertexElements, &vertexDecl);
			D3DDevice->SetVertexDeclaration(vertexDecl);
			break;
		}
	case XYZ_UV:
		{
			D3DVERTEXELEMENT9 NMVertexElements[] =  {
				{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},         
				{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},      
				D3DDECL_END()
			};
			if(vertexDecl)
				SAFE_RELEASE(vertexDecl);
			D3DDevice->CreateVertexDeclaration(NMVertexElements, &vertexDecl);
			D3DDevice->SetVertexDeclaration(vertexDecl);
			break;
		}
	case XYZ_N:
		{
			D3DVERTEXELEMENT9 NMVertexElements[] =  {
				{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},   
				{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},        
				D3DDECL_END()
			};
			if(vertexDecl)
				SAFE_RELEASE(vertexDecl);
			D3DDevice->CreateVertexDeclaration(NMVertexElements, &vertexDecl);
			D3DDevice->SetVertexDeclaration(vertexDecl);
			break;
		}
	case XYZ_UV_N:
		{
			D3DVERTEXELEMENT9 NMVertexElements[] =  {
				{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},         
				{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},    
				{0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},      
				D3DDECL_END()
			};
			if(vertexDecl)
				SAFE_RELEASE(vertexDecl);
			D3DDevice->CreateVertexDeclaration(NMVertexElements, &vertexDecl);
			D3DDevice->SetVertexDeclaration(vertexDecl);
			break;
		}
	}
}

void Mesh::Draw()
{
	D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numVertices, 0, numTriangles);
}

void Mesh::SetStream()
{	
	D3DDevice->SetStreamSource(0, vertexBuffer, 0, sizeofVertex);
	D3DDevice->SetIndices(indexBuffer);
}

void Mesh::CaculateNormals()
{
	for(int i = 0; i < numVertices; ++i){
		normalData[i] = Vector3::Zero;
	}

	for(int i = 0; i < numTriangles; ++i){
		Vector3 v0 = positionData[indexData[3*i + 0]];
		Vector3 v1 = positionData[indexData[3*i + 1]];
		Vector3 v2 = positionData[indexData[3*i + 2]];

		Vector3 v0v1 = v1 - v0;
		Vector3 v0v2 = v2 - v0;

		Vector3 normal = v0v1.Cross(v0v2);
		normal.normalize();

		normalData[indexData[3*i + 0]] = normalData[indexData[3*i + 0]] + normal;
		normalData[indexData[3*i + 1]] = normalData[indexData[3*i + 1]] + normal;
		normalData[indexData[3*i + 2]] = normalData[indexData[3*i + 2]] + normal;
	}

	for(int i = 0; i < numVertices; ++i){
		normalData[i].normalize();
	}
}